import numpy as np
import matplotlib.pyplot as plt
import csv

# hyperparameters
INPUT_DIM = 8
OUTPUT_DIM = 1
HIDDEN_UNIT_NUM = 30
EPOCH_NUM = 10000
LEARN_RATE = 0.03
MIN_ERROR = 1e-3
BATCH_SIZE = 14


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def main():
    # csv data loader
    csv_file=csv.reader(open('data_percent.csv','r'))
    cols=[]
    for col in csv_file:
        cols.append(col)
    gdp=cols.pop()

    # normalize
    input_x=np.mat(cols, dtype='float')
    input_y = np.mat(gdp, dtype='float')
    input_x_min_max = np.array([input_x.min(axis=1).T.tolist()[0], input_x.max(axis=1).T.tolist()[0]]).transpose()
    input_y_min_max = np.array([input_y.min(axis=1).T.tolist()[0], input_y.max(axis=1).T.tolist()[0]]).transpose()
    x_norm = (2 * (np.array(input_x.T) - input_x_min_max.transpose()[0]) /
              (input_x_min_max.transpose()[1] - input_x_min_max.transpose()[0]) - 1).transpose()
    y_norm = (2 * (np.array(input_y.T).astype(float) - input_y_min_max.transpose()[0]) /
              (input_y_min_max.transpose()[1] - input_y_min_max.transpose()[0]) - 1).transpose()

    # random init
    w1 = 0.5 * np.random.rand(HIDDEN_UNIT_NUM, INPUT_DIM) - 0.1
    b1 = 0.5 * np.random.rand(HIDDEN_UNIT_NUM, 1) - 0.1
    w2 = 0.5 * np.random.rand(OUTPUT_DIM, HIDDEN_UNIT_NUM) - 0.1
    b2 = 0.5 * np.random.rand(OUTPUT_DIM, 1) - 0.1
    errors = []

    for i in range(EPOCH_NUM):
        out1 = sigmoid((np.dot(w1, x_norm).transpose() + b1.transpose())).transpose()
        out2 = (np.dot(w2, out1).transpose() + b2.transpose()).transpose()
        err = y_norm - out2
        sum_sq_err = sum(sum(err ** 2))
        errors.append(sum_sq_err)
        if sum_sq_err <= MIN_ERROR:
            break
        # back propagation
        delta2 = err
        delta1 = np.dot(w2.transpose(), delta2) * out1 * (1 - out1)

        dw2 = np.dot(delta2, out1.transpose())
        db2 = np.dot(delta2, np.ones((BATCH_SIZE, 1)))
        w2 += LEARN_RATE * dw2
        b2 += LEARN_RATE * db2

        dw1 = np.dot(delta1, x_norm.transpose())
        db1 = np.dot(delta1, np.ones((BATCH_SIZE, 1)))
        w1 += LEARN_RATE * dw1
        b1 += LEARN_RATE * db1


    out1 = sigmoid((np.dot(w1, x_norm).transpose() + b1.transpose())).transpose()
    out2 = (np.dot(w2, out1).transpose() + b2.transpose()).transpose()
    diff = input_y_min_max[:, 1] - input_y_min_max[:, 0]
    predict = (out2 + 1) / 2
    predict[0] = predict[0] * diff[0] + input_y_min_max[0][0]
    input_y = np.array(input_y)

    axes = plt.gca()
    line1, = axes.plot(predict[0], 'g')
    line2, = axes.plot(input_y[0], 'r')
    axes.legend((line1, line2), ('model output', 'real output'))
    axes.set_ylabel('GDP growth percent')
    axes.set_xlabel('year')
    axes.set_title('GDP growth predict')
    plt.show()


if __name__=='__main__':
    main()